﻿using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System;
using System.Reflection;
using System.Text;
using System.IO;
using System.Diagnostics;

public static partial class SerializeHelper {

    public static string battleScriptsDirectory => Path.Combine(Application.dataPath, "0A2_Scripts/Shared/BattleData");
    public static string scriptsDirectory =>Path.Combine(Application.dataPath , "0A2_Scripts/Shared/LogicData");//BattleData
    static string protectPath
    {
        get
        {
            //return Path.Combine(Application.dataPath, "../../");
            string dataPath = Application.dataPath.Replace("\\", "/");
            string path = dataPath.Replace("ChatAppUnity/Assets", "");
            if (path[path.Length - 1] == '/')
                path = path.Substring(0, path.Length-1);
            return path;
        }
    }

    static string protoOutputPath => protectPath + "/ProtoGen/Proto/Logic";
    static string cSharpTempOutputPath => protectPath + "/ProtoGen/Export";
    static string cSharpOutputPath => scriptsDirectory + "/Serialize_Auto";

   // [MenuItem("Data/生成序列化Proto2")]
    static void GenerateProto2buf()
    {
        string preText = "using System.Collections.Generic;";
        GenerateProtobuf(2, preText,"","BattleData",scriptsDirectory,protoOutputPath,cSharpTempOutputPath);
    }

    static void GenerateProtobuf(int protoVersion,string preText,string onlyGenerateClass,string assembly,string scriptsDir ,string protoOutputPath,string cSharpTempOutputPath)
    {
        Assembly bataData = Assembly.Load(assembly);

        List<CSharpClass> classes = GetCSharpClasses(assembly,scriptsDir);

        /*var sc = Resources.Load<SharedClasses>("Data/SharedClasses");
        if(sc)
            sc.classes = classes;*/

        foreach (var cSharpClass in classes)
        {
            if (cSharpClass.isStatic
                  || cSharpClass.isAbstract
                  )
            {
                continue;
            }
            
            if (!cSharpClass.isPartial)
            {
                GameDebug.LogError($" className:{cSharpClass.Name} 未标记为 partial");
                return;
            }
        }
        if (string.IsNullOrEmpty(onlyGenerateClass))
        {
            GenerateEntityTypes(classes,scriptsDir);
            GenerateCoreDataFactoryMethods(classes,scriptsDir);
            GenerateDataPrintHelper(classes,scriptsDir);
        }

        string text = preText+ "\n\n";
        
        DirClearFiles(protoOutputPath);

        foreach (var cSharpClass in classes)
        {
            if (cSharpClass.isStatic
                || cSharpClass.isAbstract)
            {
               // GameDebug.Log($"{cSharpClass.Name}isStatic ||isAbstract :{cSharpClass.keys.GetArrStr()}");
                continue;
            }

            if (cSharpClass.type == null)
            {
                GameDebug.LogError($"null  className:{cSharpClass.Name}");
                continue;
            }
            
        
            if (!string.IsNullOrEmpty(onlyGenerateClass))
            {
                if (!cSharpClass.Name.Contains(onlyGenerateClass))
                    continue;
            }
#if LOG
            GameDebug.Log($"将生成 :{cSharpClass.Name}   protoOutputPath:{protoOutputPath}");
#endif

            if(protoVersion == 2)
                text += GenerateProto2Sharp(cSharpClass.type) + "\n\n";
            else
                text += GenerateProto3(protoOutputPath,cSharpClass.type) + "\n\n";

        }

        if(string.IsNullOrEmpty(onlyGenerateClass))
            SaveFile(Path.Combine(scriptsDir,"Serialized_Auto.cs"), text);
        else
            SaveFile(Path.Combine(scriptsDir, $"{onlyGenerateClass}_AutoCode.cs"), text);

        try
        {
            if (protoVersion == 3)
                Proto2Sharp(scriptsDir,protoOutputPath,cSharpTempOutputPath);
        }
        catch(Exception e)
        {
            GameDebug.LogError(e);
        }
        AssetDatabase.Refresh();
    }

    static List<CSharpClass> GetCSharpClasses(string assembly,string scriptsDirectory)
    {
        Assembly bataData = Assembly.Load(assembly);

        List<CSharpClass> classes = new List<CSharpClass>();

        string[] sharps = Directory.GetFiles(scriptsDirectory, "*.cs");
        foreach (var sharp in sharps)
        {
            if (sharp.Contains("CoreEntityCollection"))
            {
                continue;
            }
            //if (sharp.Contains("MessagePacket"))
            //{
            //    continue;
            //}

            //if (sharp.Contains("_Ext"))
            //    continue;

            //if (sharp.Contains("_Auto"))
            //    continue;

            if (Path.GetFileNameWithoutExtension(sharp).Contains("_"))
                continue;
            
            string sharpFile = GetFileNameWithPath(sharp, true);

            var newclasses = ParseClass(bataData, sharp, "class");
            var newStructs = ParseClass(bataData, sharp, "struct");

            foreach (var newc in newclasses)
            {
                if (classes.Find(e=>e.Name == newc.Name) == null)
                {
                    classes.Add(newc);
                }
            } 
            foreach (var news in newStructs)
            {
                if (classes.Find(e=>e.Name == news.Name) == null)
                {
                    classes.Add(news);
                }
            }
        }

        GameDebug.Log($"class type num :{classes.Count}   sharps count:{sharps.Length}");

        return classes;
    }

    /*[MenuItem("Data/生成EntityType")]
    static void TestGenerateEntityTypes()
    {
        List<CSharpClass> classes = GetCSharpClasses(scriptsDirectory);
        GenerateEntityTypes(classes,scriptsDirectory);
    }*/

    [MenuItem("Data/生成CoreDataEntity获取方法")]
    static void TestGenerateCoreDataEntityMethods()
    {
        List<CSharpClass> classes = GetCSharpClasses("BattleData",scriptsDirectory);
        GenerateCoreDataFactoryMethods(classes,scriptsDirectory);
    }

    /// <summary>
    /// 生成EntityTypes
    /// </summary>
    /// <param name="classes"></param>
    static void GenerateEntityTypes(List<CSharpClass> classes,string scriptsDirectory)
    {
        List<string> CoreDataEntityTypes = new List<string>();

        foreach (var cSharpClass in classes)
        {
            if (CheckTypeIsChildOfCoreDataEntity(cSharpClass.type, false) && !cSharpClass.isAbstract)
            {
                if(!CoreDataEntityTypes.Contains(cSharpClass.type.ToString()))
                    CoreDataEntityTypes.Add(cSharpClass.type.ToString());
            }
        }
        if (CoreDataEntityTypes.Count > 0)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("public static class EntityType\n");
            sb.Append("{\n");

            for (int i = 0; i < CoreDataEntityTypes.Count; i++)
            {
                sb.Append($"\tpublic const int {CoreDataEntityTypes[i]} = {i};\n");
            }

            sb.Append("\n\tpublic static string[] text = new string[]\n");
            sb.Append("\t{\n\t\t");
            for (int i = 0; i < CoreDataEntityTypes.Count; i++)
            {
                if (i == CoreDataEntityTypes.Count)
                    sb.Append($"\"{CoreDataEntityTypes[i]}\"");
                else
                    sb.Append($"\"{CoreDataEntityTypes[i]}\",");
            }
            sb.Append("\n\t};\n");

            sb.Append("\n\tpublic static string GetTypeStrWithTypeId(int type)\n");
            sb.Append("\t{\n");
            sb.Append("\t    if (type >= 0 && type < text.Length)\n");
            sb.Append("\t    {\n");
            sb.Append("\t        return text[type];\n");
            sb.Append("\t    }\n");
            sb.Append("\t   return \"unknown\";\n");
            sb.Append("\t}\n");

             sb.Append("\n\tpublic static int GetTypeIDWithType(System.Type dataType)\n");
            sb.Append("\t{\n");
            sb.Append("\t    for (int i = 0; i < text.Length; i++)\n");
            sb.Append("\t    {\n");
            sb.Append("\t        if (text[i].Equals(dataType.Name))\n");
            sb.Append("\t        {\n");
            sb.Append("\t            return i;\n");
            sb.Append("\t        }\n");
            sb.Append("\t    }\n");
            sb.Append("\t    GameDebug.LogError(\"cannot find type :{dataType.Name}\");\n");
            sb.Append("\t    return -1;\n");
            sb.Append("\t}\n");

            sb.Append("}\n");

            SaveFile(Path.Combine(scriptsDirectory, "EntityType_Auto.cs"), sb.ToString());
        }
    }

    /// <summary>
    /// 生成EntityTypes DataPrintHelper
    /// </summary>
    /// <param name="classes"></param>
    static void GenerateDataPrintHelper(List<CSharpClass> classes,string scriptsDirectory)
    {
        List<string> CoreDataEntityTypes = new List<string>();

        foreach (var cSharpClass in classes)
        {
            if (CheckTypeIsChildOfCoreDataEntity(cSharpClass.type, false) && !cSharpClass.isAbstract)
            {
                if (!CoreDataEntityTypes.Contains(cSharpClass.type.ToString()))
                    CoreDataEntityTypes.Add(cSharpClass.type.ToString());
            }
        }
        if (CoreDataEntityTypes.Count > 0)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("using System;\n\n");
            sb.Append("public static partial class GameDataPrintHelper\n");
            sb.Append("{\n");

            sb.Append("\tpublic static string PrintCoreDataEntityValue(CoreDataEntity CoreDataEntity)\n");
            sb.Append("\t{\n");
            sb.Append("\t\tint typeId = CoreDataEntity.GetEntityTypeID();\n\n");

            for (int i = 0; i < CoreDataEntityTypes.Count; i++)
            {
                sb.Append($"\t\tif (typeId == EntityType.{CoreDataEntityTypes[i]}) return PrintObjectValue<{CoreDataEntityTypes[i]}>(CoreDataEntity);\n");
            }
            sb.Append("\n\t\treturn \"\";\n");
            sb.Append("\n\t}\n");

            sb.Append("\tpublic static string GetListCoreDataEntityValue(Type innerType, object listCoreDataEntity)\n");
            sb.Append("\t{\n");

            for (int i = 0; i < CoreDataEntityTypes.Count; i++)
            {
                sb.Append($"\t\t if (innerType.Equals(typeof({CoreDataEntityTypes[i]}))) return GetListEntityValue<{CoreDataEntityTypes[i]}>(listCoreDataEntity);\n");
            }
            sb.Append("\n\t\treturn \"\";\n");
            sb.Append("\n\t}\n");

            sb.Append("\n}\n");

            SaveFile(Path.Combine(scriptsDirectory+ "/Common", "GameDataPrintHelper_Auto.cs"), sb.ToString());
        }
    }

    /// <summary>
    /// 生成CoreDataEntityFactory 方法
    /// </summary>
    /// <param name="classes"></param>
    static void GenerateCoreDataFactoryMethods(List<CSharpClass> classes,string scriptsDirectory)
    {
        List<string> coreDataEntityTypes = new List<string>();

        foreach (var cSharpClass in classes)
        {
            if (CheckTypeIsChildOfCoreDataEntity(cSharpClass.type, false) && !cSharpClass.isAbstract)
            {
                if(!coreDataEntityTypes.Contains(cSharpClass.type.ToString()))
                    coreDataEntityTypes.Add(cSharpClass.type.ToString());
            }
        }

        GameDebug.Log($"generate EntityType:{coreDataEntityTypes.GetListStr()}");
        
        if(coreDataEntityTypes.Count > 0)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("using System;\n");
            sb.Append("public static partial class CoreDataEntityFactory\n");
            sb.Append("{\n");

            //////
            sb.Append("\tstatic Func<CoreDataEntity>[] EntityFactory = new Func<CoreDataEntity>[]\n");
            sb.Append("\t{\n");
            for (int i=0;i< coreDataEntityTypes.Count;i++)
            {
                sb.Append($"\t\t{coreDataEntityTypes[i]}.NewEntity,\n");
            }
            sb.Append("\t};\n");
            
            //////
            sb.Append("\n\tpublic static CoreDataEntity EntityReadBytes(Type type , CoreDataEntity newEntity , byte[] bytes)\n");
            sb.Append("\t{\n");

            sb.Append("\t\ttry\n");

            sb.Append("\t\t{\n");

            for (int i = 0; i < coreDataEntityTypes.Count; i++)
            {
                sb.Append($"\t\t\t{(i == 0 ? "" : "else ")}if (type.Equals(typeof({coreDataEntityTypes[i]})))\n");
                sb.Append($"\t\t\t\t(newEntity as {coreDataEntityTypes[i]}).Read(bytes);\n");
            }
            sb.Append("\t\t\telse\n");
            sb.Append("\t\t\t\tGameDebug.LogError($\"type convert error   typeID:{newEntity.GetEntityTypeID()}\");\n");

            sb.Append("\t\t}\n");
                
            sb.Append("\t\tcatch (Exception e)\n");
            sb.Append("\t\t{\n");
            sb.Append("\t\t\tGameDebug.LogException(e);\n");
            sb.Append("\t\t}\n");
                
            sb.Append("\t\treturn newEntity;\n");

            sb.Append("\t}\n");
            ///////
            sb.Append("\n\tpublic static byte[] GetBytesWithType(Type type,CoreDataEntity CoreDataEntity)\n");
            sb.Append("\t{\n");

            sb.Append("\t\tif (type == null)\n");
            sb.Append("\t\t{\n");
            sb.Append("\t\t\tGameDebug.LogError($\"type == null typeID:{CoreDataEntity?.GetEntityTypeID()}\");\n");
            sb.Append("\t\t\treturn null;\n");
            sb.Append("\t\t}\n");

            sb.Append("\t\tif (CoreDataEntity == null)\n");
            sb.Append("\t\t{\n");
            sb.Append("\t\t    GameDebug.LogError($\"CoreDataEntity == null type:{type}\");\n");
            sb.Append("\t\t    return null;\n");
            sb.Append("\t\t}\n");

            for (int i = 0; i < coreDataEntityTypes.Count; i++)
            {
                sb.Append($"\t\t{(i == 0 ? "" : "else ")}if (type.Equals(typeof({coreDataEntityTypes[i]})))\n");
                sb.Append($"\t\t\t return (CoreDataEntity as {coreDataEntityTypes[i]}).Write();\n");
            }

            sb.Append("\n\t\tGameDebug.LogError($\"get bytes failed, type:{type} \");\n");
            sb.Append("\t\treturn null;\n");

            sb.Append("\t}\n");

            sb.Append("}\n");


            SaveFile(Path.Combine(scriptsDirectory, "CoreDataEntityFactory_Auto.cs"), sb.ToString());
        }
    }


    /// <summary>
    /// 生成proto2序列化文件
    /// </summary>
    static string GenerateProto2Sharp(Type type)
    {
        Assembly bataData = Assembly.Load("BattleData");

        FieldInfo[] fields = GetSerilizedFields(type);

        StringBuilder protoText = new StringBuilder();

        string newTypeName = GetGenerateDataTypeName(type);

        //protoText.Append("using System.Collections.Generic;\n\n\n");

        protoText.Append($"[global::System.Serializable, global::ProtoBuf.ProtoContract(Name = @\"{newTypeName}\")] \n");

        bool isStruct = type.IsValueType;


        if(isStruct)
            protoText.Append($"public partial struct  {newTypeName}");
        else
            protoText.Append($"public partial class  {newTypeName}: global::ProtoBuf.IExtensible");

        protoText.Append("\n{\n");

        if (!isStruct)
            protoText.Append(string.Format("\tpublic {0}() {{}}\n\n", newTypeName));

        int index = 1;
        for (int i = 0; i < fields.Length; i++)
        {
            //是列表或Array
            if (CheckTypeListOrArray(fields[i].FieldType))
            {
                //非基本类型
                if (!IsBaseType(GetListOrArrayInnerTypeString(fields[i].FieldType)))
                {
                    string innerTypeStr = GetListOrArrayInnerTypeString(fields[i].FieldType);
                    Type innerType = bataData.GetType(innerTypeStr);

                    protoText.Append(GetFieldProto2Text(typeof(int), fields[i].Name + "_Count", index));

                    index++;

                    protoText.Append(GetFieldProto2Text(typeof(List<int>), fields[i].Name + "_Indexes", index));

                    index++;

                    //是CoreDataEntity
                    if (CheckTypeIsChildOfCoreDataEntity(innerType))
                    {
                        //protoText.Append(GetFieldProtoText(typeof(List<int>), fields[i].Name + "_EntityTypes", index));

                        //index++;

                        protoText.Append(GetFieldProto2Text(typeof(List<int>), fields[i].Name + "_EntityIDs", index));

                        index++;
                    }
                    else
                    {
                        if(IsSerializedBaseType(innerType))
                        {
                            protoText.Append(GetFieldProto2Text(typeof(List<int>), fields[i].Name+"_Types", index));

                            index++;
                        }
                        protoText.Append(GetFieldProto2Text(fields[i].FieldType, fields[i].Name, index));

                        index++;
                    }
                }
                else
                {
                    protoText.Append(GetFieldProto2Text(fields[i].FieldType, fields[i].Name, index));

                    index++;
                }
            }
            else
            //不是列表,不是Array
            {
                //是CoreDataEntity
                if (CheckTypeIsChildOfCoreDataEntity(fields[i].FieldType))
                {
                    //protoText.Append(GetFieldProtoText(typeof(int), fields[i].Name + "_EntityType", index));

                    //index++;

                    protoText.Append(GetFieldProto2Text(typeof(int), fields[i].Name + "_EntityID", index));

                    index++;
                }
                else
                {
                    if (IsSerializedBaseType(fields[i].FieldType))
                    {
                        protoText.Append(GetFieldProto2Text(typeof(int), fields[i].Name + "_Type", index));

                        index++;
                    }
                    protoText.Append(GetFieldProto2Text(fields[i].FieldType, fields[i].Name, index));

                    index++;
                }
            }
 
        }

        if (!isStruct)
            protoText.Append("\tprivate global::ProtoBuf.IExtension extensionObject;\n\tglobal::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)\n\t{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }");

        protoText.Append("\n}");

        protoText.Append(GenerateProto2SharpSerialize(type));
        //GameDebug.Log($"生成:{protoText}");

        //SaveFile(Path.Combine(scriptsDirectory,type.FullName+"_Auto.cs"), protoText.ToString());
        return protoText.ToString();
    }


    /// <summary>
    /// 生成序列化文件
    /// </summary>

    //[MenuItem("Data/生成Proto2EntityCollection Proto序列化")]
    //static void GenerateProto2EntityCollectionProtoSharp()
    //{
    //    Type type = typeof(CoreEntityCollection);

    //    Assembly bataData = Assembly.Load("BattleData");

    //    FieldInfo[] fields = GetSerilizedFields(type);

    //    StringBuilder protoText = new StringBuilder();

    //    string newTypeName = GetGenerateDataTypeName(type);

    //    protoText.Append("using System.Collections.Generic;\n\n\n");

    //    protoText.Append($"[global::System.Serializable, global::ProtoBuf.ProtoContract(Name = @\"{newTypeName}\")] \n");
        
    //    protoText.Append($"public partial class  {newTypeName}: global::ProtoBuf.IExtensible");

    //    protoText.Append("\n{\n");
        
    //    protoText.Append(string.Format("\tpublic {0}() {{}}\n\n", newTypeName));

    //    int index = 1;
    //    for (int i = 0; i < fields.Length; i++)
    //    {
    //        //是列表或Array
    //        if (CheckTypeListOrArray(fields[i].FieldType))
    //        {
    //            //非基本类型
    //            if (!IsBaseType(GetListOrArrayInnerTypeString(fields[i].FieldType)))
    //            {
    //                string innerTypeStr = GetListOrArrayInnerTypeString(fields[i].FieldType);
    //                Type innerType = bataData.GetType(innerTypeStr);

    //                protoText.Append(GetFieldProto2Text(typeof(int), fields[i].Name + "_Count", index));

    //                index++;

    //                protoText.Append(GetFieldProto2Text(typeof(List<int>), fields[i].Name + "_Indexes", index));

    //                index++;

    //                //是CoreDataEntity
    //                if (CheckTypeIsChildOfCoreDataEntity(innerType))
    //                {
    //                    protoText.Append(GetFieldProto2Text(typeof(List<int>), fields[i].Name + "_EntityTypes", index));

    //                    index++;

    //                    protoText.Append(GetFieldProto2Text(typeof(List<int>), fields[i].Name + "_EntityIDs", index));

    //                    index++;
    //                }

    //                protoText.Append(GetFieldProto2Text(fields[i].FieldType, fields[i].Name, index));

    //                index++;
    //            }
    //            else
    //            {
    //                protoText.Append(GetFieldProto2Text(fields[i].FieldType, fields[i].Name, index));

    //                index++;
    //            }
    //        }
    //        else
    //        //不是列表,不是Array
    //        {
    //            //是CoreDataEntity
    //            if (CheckTypeIsChildOfCoreDataEntity(fields[i].FieldType))
    //            {
    //                protoText.Append(GetFieldProto2Text(typeof(int), fields[i].Name + "_EntityType", index));

    //                index++;

    //                protoText.Append(GetFieldProto2Text(typeof(int), fields[i].Name + "_EntityID", index));

    //                index++;
    //            }
                
    //            protoText.Append(GetFieldProto2Text(fields[i].FieldType, fields[i].Name, index));

    //            index++;
    //        }

    //    }

    //    protoText.Append("\tprivate global::ProtoBuf.IExtension extensionObject;\n\tglobal::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)\n\t{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }");

    //    protoText.Append("\n}");

    //    //protoText.Append(GenerateEntityCollectionSharpSerialize());
    //    //GameDebug.Log($"生成:{protoText}");

    //    SaveFile(Path.Combine(scriptsDirectory, type.FullName + "_Auto.cs"), protoText.ToString());
    //}

    public static bool CheckTypeListOrArray(Type type)
    {
        string fieldTypeStr = type.ToString();
        if (fieldTypeStr.Contains("List")
            || fieldTypeStr.Contains("[]"))
            return true;

        return false;
    }
    static bool CheckTypeList(Type type)
    {
        string fieldTypeStr = type.ToString();
        if (fieldTypeStr.Contains("List"))
            return true;

        return false;
    }
    static string GetFieldProto2Text(Type type,string fieldName,int index)
    {
        StringBuilder protoText = new StringBuilder();

        string fieldTypeStr = type.ToString();

        if (!IsBaseType(type))
        {
            fieldTypeStr = "byte[]";
        }

        string fieldNameStr = "__" + fieldName;
        string propertNameStr = "_" + fieldName;

        string fieldStr = string.Format("private {0} {1};", fieldTypeStr, fieldNameStr);

        protoText.Append("\t" + fieldStr + "\n");

        // GameDebug.Log($"field:{fields[i].Name} type:{fields[i].FieldType}");

        string dataFormatStr = Type2ProtoBufDataFormat(type);
        string formatStr = string.Format("[global::ProtoBuf.ProtoMember({0}, IsRequired = true, Name = @\"{1}\", DataFormat = global::ProtoBuf.DataFormat.{2})]", index, propertNameStr, dataFormatStr);

        protoText.Append("\t" + formatStr + "\n");

        string propertyStr = string.Format("\tpublic {0} {1}\n\t{{\n\t\tget{{return {2};}}\n\t\tset{{{3} = value;}}\n\t}}", fieldTypeStr, propertNameStr, fieldNameStr, fieldNameStr);
        protoText.Append(propertyStr + "\n");

        return protoText.ToString();
    }

    static string GetGenerateDataTypeName(Type type)
    {
        return type.Name + "_Data";
    }

    /// <summary>
    /// 生成序列化反序列化方法
    /// </summary>
    static string GenerateProto2SharpSerialize(Type type)
    {
        FieldInfo[] fields = GetSerilizedFields(type);

        Assembly bataData = Assembly.Load("BattleData");

        StringBuilder sb = new StringBuilder();

        string dataTypeName = GetGenerateDataTypeName(type);

        sb.Append("\n\n");

        bool isStruct = type.IsValueType;

        bool isParentInheritedFromISerialize = CheckTypeIsChildOfISerializeOrISerializeStruct(type.BaseType);

        //sb.Append($"public partial {(isStruct?"struct":"class")} {type.Name} {(inheritedFromCoreDataEntity? "": ": ISerialize")} \n");

        if (isStruct)
        {
            sb.Append($"public partial struct {type.Name} :ISerializeStruct \n");
        }
        else
        {
            sb.Append($"public partial class {type.Name} {(isParentInheritedFromISerialize ? "" : ": ISerialize")} \n");
        }

        sb.Append("{\n");

        //bool hasEmptyConstructor = false;

        //ConstructorInfo[] cis = type.GetConstructors();

        //foreach(var ci in cis)
        //{
        //    if (ci.GetParameters().Length <= 0)
        //    {
        //        GameDebug.Log($"类{type}有无参构造函数");
        //        hasEmptyConstructor = true;
        //    }
        //    else
        //    {
        //        GameDebug.Log($"类{type}有有参构造函数  参数数：{ci.GetParameters().Length }");
        //    }
        //}

        //if (!isStruct && !hasEmptyConstructor)
        if (!isStruct)
        {
            if(!IsChildOfSerializedBaseType(type.BaseType))//OptBase子类特殊处理
                sb.Append(string.Format("\tpublic {0}():base() {{}}\n\n", type.Name));
        }
        sb.Append($"\n\tpublic static {type.Name} NewEntity()\n");
        sb.Append("\t{\n");
        sb.Append($"\t\treturn new {type.Name}();\n");
        sb.Append("\t}\n");

        if (CheckTypeIsChildOfCoreDataEntity(type,false))
        {
            sb.Append($"\n\tpublic override int GetEntityTypeID()\n");
            sb.Append("\t{\n");
            sb.Append($"\t    return EntityType.{type.Name};\n");
            sb.Append("\t}\n");
        }
        ///反序列化
        sb.Append($"\n\tpublic {(isStruct?"":"override")} void Read(byte[] bytes)\n");
            sb.Append("\t{\n");

               sb.Append($"\t\tif(bytes == null) return;\n");

               sb.Append($"\t\t{dataTypeName} data = CommonFunctions.Deserialize<{dataTypeName}>(bytes);\n");

                if (!isStruct)
                {
                    sb.Append($"\t\tif (null == data)\n");
                    sb.Append("\t\t{\n");
                    sb.Append($"\t\t    GameDebug.LogError(\"{dataTypeName} deserialize failed\");\n");
                    sb.Append("\t\t}\n");
                }

                for (int i = 0; i < fields.Length; i++)
                {
                    if (!IsBaseType(fields[i].FieldType))
                    {
                        if (CheckTypeListOrArray(fields[i].FieldType) && !IsBaseType(GetListOrArrayInnerTypeString(fields[i].FieldType)))
                        {
               ///是否是列表 而且内部元素不是基本类型
                            string innerTypeStr = GetListOrArrayInnerTypeString(fields[i].FieldType);
                            Type innerType = bataData.GetType(innerTypeStr);

                            if (CheckTypeIsChildOfCoreDataEntity(innerType))
                                continue;

                            string countName = $"_{fields[i].Name}_Count";
                            string indexesName = $"_{fields[i].Name}_Indexes";
                            //string entityTypesName = $"_{fields[i].Name}_EntityTypes";
                            string entityIDsName = $"_{fields[i].Name}_EntityIDs";
                            string typeIDsName = $"_{fields[i].Name}_Types";

                            sb.Append($"\n\t\tint {countName} = data.{countName};\n");

                            if (CheckTypeList(fields[i].FieldType))
                            {
                                sb.Append($"\t\t{fields[i].Name} = new List<{innerTypeStr}>();\n\n");
                            }
                            else
                            {
                                sb.Append($"\t\t{fields[i].Name} = new {innerTypeStr}[{countName}];\n\n");
                            }
                            
                            if (CheckTypeIsChildOfCoreDataEntity(innerType))
                            {
                                //sb.Append($"\t\t\tList<int> {entityTypesName} =  CommonFunctions.Deserialize<List<int>>(data.{entityTypesName});\n");
                                sb.Append($"\t\t\tList<int> {entityIDsName} =  CommonFunctions.Deserialize<List<int>>(data.{entityIDsName});\n");
                            }
                          
                            else
                            {
                                if (IsSerializedBaseType(innerType))//OptBase特殊处理
                                {
                                    sb.Append($"\t\t\tList<int> {typeIDsName} =  CommonFunctions.Deserialize<List<int>>(data.{typeIDsName});\n");
                                }

                                sb.Append($"\t\tList<int> {indexesName} =  CommonFunctions.Deserialize<List<int>>(data.{indexesName});\n");
                            }

                            sb.Append($"\t\tfor(int i=0;i<{countName};i++)\n");
                            sb.Append("\t\t{\n");

                            if (innerType != null)
                            {
                                bool innerTypeIsStruct = innerType.IsValueType;

                                if (CheckTypeIsChildOfCoreDataEntity(innerType))//.BaseType.GetField("m_EntityId") != null)
                                {
                                    sb.Append($"\t\t\tvar newObj = CoreDataEntityFactory.GetEntity<{innerType}>({entityIDsName}[i]) as {innerType};\n");
                                }
                                else
                                {
                                    sb.Append($"\t\t\tint curIndex = {indexesName}[i];\n");

                                    sb.Append($"\t\t\tint curLength = ((i+1)<{indexesName}.Count? {indexesName}[i+1]:{indexesName}.Count) - curIndex;\n");

                                    sb.Append("\t\t\tbyte[] ebytes = new byte[curLength];\n");

                                    sb.Append($"\t\t\tSystem.Array.Copy(data._{ fields[i].Name},curIndex,ebytes,0,curLength);\n");

                                    if (!innerTypeIsStruct)
                                    {
                                        sb.Append($"\n\t\t\t{innerTypeStr} newObj = null;\n");

                                        //sb.Append($"\t\t\tif({fields[i].Name} == null) \n");
                                
                                        if (IsSerializedBaseType(innerType))//特殊处理
                                        {
                                            //if (CheckTypeList(fields[i].FieldType))
                                            //{
                                            //    sb.Append($"\t\t\t\t{fields[i].Name} = new List<{innerTypeStr}>();\n\n");
                                            //}
                                            //else
                                            //{
                                            //    sb.Append($"\t\t\t\t{fields[i].Name} = new {innerTypeStr}[{countName}];\n\n");
                                            //}
                                            sb.Append($"\t\t\tint curType = {typeIDsName}[i];\n");

                                            sb.Append($"\t\t\tnewObj = {innerType.Name}.ReadBytes(curType,ebytes);\n\n");
                                        }
                                        else
                                        {
                                            if (CheckTypeList(fields[i].FieldType))
                                            {
                                                //sb.Append($"\t\t\t\t{fields[i].Name} = new List<{innerTypeStr}>();\n\n");
                                                sb.Append($"\t\t\tif(i<{fields[i].Name}.Count && {fields[i].Name}[i] != null)\n");
                                            }
                                            else
                                            {
                                                //sb.Append($"\t\t\t\t{fields[i].Name} = new {innerTypeStr}[{countName}];\n\n");
                                                sb.Append($"\t\t\tif(i<{fields[i].Name}.Length && {fields[i].Name}[i] != null)\n");
                                            }

                                            //  sb.Append($"\t\t\tif(i<{fields[i].Name}.{(CheckTypeList(fields[i].FieldType)?"Count":"Length")} && {fields[i].Name}[i] != null)\n");

                                            sb.Append($"\t\t\t\t newObj = {fields[i].Name}[i];\n");
                                            sb.Append($"\t\t\telse\n");
                                            sb.Append($"\t\t\t\t newObj = {innerTypeStr}.NewEntity();\n\n");

                                            sb.Append($"\t\t\tnewObj.Read(ebytes);\n\n");
                                        }
                                    }
                                    else
                                    {
                                        sb.Append($"\n\t\t\t{innerTypeStr} newObj =  {innerTypeStr}.NewEntity();\n");
                                        //sb.Append($"\t\t\tif({fields[i].Name} == null) \n");

                                      
                                        //  sb.Append($"\t\t\tif(i<{fields[i].Name}.{(CheckTypeList(fields[i].FieldType)?"Count":"Length")} && {fields[i].Name}[i] != null)\n");
                                        
                                        sb.Append($"\t\t\tnewObj.Read(ebytes);\n\n");
                                    }
                                }
                            }
                            else
                            {
                                GameDebug.LogError($"innerType == null innerTypeStr:{innerTypeStr}");
                                sb.Append($"\t\t\tvar newObj = new {innerTypeStr}();\n");
                                sb.Append($"\t\t\tnewObj.Read(ebytes);\n\n");
                            }

                            if (CheckTypeList(fields[i].FieldType))
                                sb.Append($"\t\t\t{fields[i].Name}.Add(newObj);\n");
                            else
                                sb.Append($"\t\t\t{fields[i].Name}[i] = newObj;\n");

                            sb.Append("\t\t}\n\n");
                        }
                        else
                        {
                            if (CheckTypeIsChildOfISerializeOrISerializeStruct(fields[i].FieldType))
                            {
                      
                                GameDebug.Log($"{fields[i].Name}是ISerialize");
                                bool fieldIsStruct = fields[i].FieldType.IsValueType;
                                if (!fieldIsStruct)
                                {
                                    if (IsSerializedBaseType(fields[i].FieldType))//OptBase 特殊处理
                                    {
                                        string typeIDName = $"_{fields[i].Name}_Type";
                                        sb.Append($"\t\tint optType = data.{typeIDName};\n");

                                        sb.Append($"\t\tthis.{fields[i].Name} = {fields[i].FieldType.Name}.ReadBytes(optType,data._{ fields[i].Name});\n");
                                    }
                                    else if (CheckTypeIsChildOfCoreDataEntity(fields[i].FieldType))//.BaseType.GetField("m_EntityId") != null)
                                    {
                                        continue;
                                    }
                                    else
                                    {
                                        sb.Append($"\t\tif(this.{fields[i].Name} == null)\n");
                                        sb.Append($"\t\t\tthis.{fields[i].Name} = {GetListOrArrayInnerTypeString(fields[i].FieldType)}.NewEntity();\n\n");
                                        sb.Append($"\t\tthis.{fields[i].Name}.Read(data._{fields[i].Name});\n\n");
                                    }
                                }
                                else
                                {
                                    sb.Append($"\t\tthis.{fields[i].Name}.Read(data._{fields[i].Name});\n");
                                }

                            }
                            else
                            {
                                if (fields[i].FieldType.Equals(typeof(byte[])))
                                {
                                    sb.Append($"\t\tthis.{fields[i].Name} = data._{fields[i].Name};\n");
                                }
                                else
                                {
                                    string typeStr = GetTypeString(fields[i].FieldType);
                                    sb.Append($"\t\tthis.{fields[i].Name} = CommonFunctions.Deserialize<{typeStr}>(data._{fields[i].Name});\n");
                                }
                            }
                        }
                    }
                    else
                    {
                        sb.Append($"\t\tthis.{fields[i].Name} = data._{fields[i].Name};\n");
                    }
                }


        bool fieldsContainsCoreDataEntity = false;

        if (!CheckTypeIsChildOfCoreDataEntity(type, false))
        {
            for (int i = 0; i < fields.Length; i++)
            {
                if (CheckTypeIsChildOfCoreDataEntity(fields[i].FieldType))
                {
                    fieldsContainsCoreDataEntity = true;
                    break;
                }
                if (CheckTypeListOrArray(fields[i].FieldType))
                {
                    string innerTypeStr = GetListOrArrayInnerTypeString(fields[i].FieldType);
                    Type innerType = bataData.GetType(innerTypeStr);
                    if (innerType != null && CheckTypeIsChildOfCoreDataEntity(innerType))
                    {
                        fieldsContainsCoreDataEntity = true;
                        break;
                    }
                }
            }
        }

        if (!CheckTypeIsChildOfCoreDataEntity(type, false) && fieldsContainsCoreDataEntity)
        {
            sb.Append("\n\t\tEntityReference(bytes);\n");
        }

        sb.Append("\t}\n");

        ///生成实体引用读取
        if (CheckTypeIsChildOfCoreDataEntity(type, false))
        { 
            sb.Append("\n\tpublic override void EntityReference(byte[] bytes,CoreEntityCollection entityCollection)\n");
        }
        else if (fieldsContainsCoreDataEntity)
        {
            sb.Append("\n\tpublic void EntityReference(byte[] bytes,CoreEntityCollection entityCollection)\n");
        }

        if (CheckTypeIsChildOfCoreDataEntity(type, false) || fieldsContainsCoreDataEntity)
        {
            sb.Append("\t{\n");

            sb.Append($"\t\tif(bytes == null) return;\n");

            sb.Append($"\t\t{dataTypeName} data = CommonFunctions.Deserialize<{dataTypeName}>(bytes);\n");

            for (int i = 0; i < fields.Length; i++)
            {
                if (!IsBaseType(fields[i].FieldType))
                {
                    if (CheckTypeListOrArray(fields[i].FieldType) && !IsBaseType(GetListOrArrayInnerTypeString(fields[i].FieldType)))
                    {
                        string innerTypeStr = GetListOrArrayInnerTypeString(fields[i].FieldType);
                        Type innerType = bataData.GetType(innerTypeStr);

                        if (CheckTypeIsChildOfCoreDataEntity(innerType))
                        {
                            string countName = $"_{fields[i].Name}_Count";
                            string indexesName = $"_{fields[i].Name}_Indexes";
                          //  string entityTypesName = $"_{fields[i].Name}_EntityTypes";
                            string entityIDsName = $"_{fields[i].Name}_EntityIDs";

                            sb.Append($"\n\t\tint {countName} = data.{countName};\n");

                            if (CheckTypeList(fields[i].FieldType))
                                sb.Append($"\t\t{fields[i].Name} = new List<{innerType}>();\n");
                            else
                                sb.Append($"\t\t{fields[i].Name} = new {innerType}[{countName}];\n");

                            //  sb.Append($"\t\tList<int> {entityTypesName} =  CommonFunctions.Deserialize<List<int>>(data.{entityTypesName});\n");
                            sb.Append($"\t\tList<int> {entityIDsName} =  CommonFunctions.Deserialize<List<int>>(data.{entityIDsName});\n");


                            sb.Append($"\t\tfor(int i=0;i<{countName};i++)\n");
                            sb.Append("\t\t{\n");

                            sb.Append($"\t\t\tvar newObj_{i} = entityCollection.GetEntity<{innerType}>({entityIDsName}[i]);\n");

                            if (CheckTypeList(fields[i].FieldType))
                                sb.Append($"\t\t\t{fields[i].Name}.Add(newObj_{i});\n");
                            else
                                sb.Append($"\t\t\t{fields[i].Name}[i] = newObj_{i};\n");

                            sb.Append("\t\t}\n");
                        }
                    }
                    else
                    {
                        if (CheckTypeIsChildOfCoreDataEntity(fields[i].FieldType))//.BaseType.GetField("m_EntityId") != null)
                        {
                            //string entityTypeName = $"_{fields[i].Name}_EntityType";
                            string entityIDName = $"_{fields[i].Name}_EntityID";
                          //  sb.Append($"\n\t\tint {entityTypeName} = data.{entityTypeName};\n");
                            sb.Append($"\t\tint {entityIDName} = data.{entityIDName};\n");

                            sb.Append($"\t\tvar newObj_{i} = entityCollection.GetEntity<{fields[i].FieldType}>({entityIDName});\n");
                            sb.Append($"\t\tthis.{fields[i].Name} = newObj_{i};\n\n");
                            //sb.Append($"\t\t\tthis.{fields[i].Name} = CoreDataEntityFactory.GetEntity<{fields[i].FieldType}>(EntityType.{fields[i].FieldType});\n");
                        }
                    }
                }

            }

            sb.Append("\t}\n");
        }

            sb.Append($"\n\tpublic {(isStruct?"":"override")} byte[] Write()\n");
            sb.Append("\t{\n");

            sb.Append($"\t\t{dataTypeName} data = new {dataTypeName}();\n");

            for (int i = 0; i < fields.Length; i++)
            {
                string dataFieldName = $"_{fields[i].Name}";
            
                if (!IsBaseType(fields[i].FieldType))
                {
                    if (CheckTypeListOrArray(fields[i].FieldType) && !IsBaseType(GetListOrArrayInnerTypeString(fields[i].FieldType)))
                    {
                        string innerTypeStr = GetListOrArrayInnerTypeString(fields[i].FieldType);
                        var innerType = Type.GetType(innerTypeStr);

                        if(innerType == null)
                            innerType = bataData.GetType(innerTypeStr);

                        bool innerIsStruct = false;
                        if (innerType != null)
                            innerIsStruct = innerType.IsValueType;
                        else
                            GameDebug.LogError($"innerType == null  innerTypeStr:{innerTypeStr}");

                        sb.Append("\n");
                        string countName = $"{dataFieldName}_Count";
                        string indexesName = $"{dataFieldName}_Indexes";
                        //string entityTypesName = $"_{fields[i].Name}_EntityTypes";
                        string entityIDsName = $"_{fields[i].Name}_EntityIDs";

                        string curIndexName = $"{fields[i].Name}_CurIndex";
                        string bytesName = $"{fields[i].Name}_Bytes";

                        string typesName = $"_{fields[i].Name}_Types";

                        sb.Append($"\t\tdata.{countName} = this.{fields[i].Name}.{(CheckTypeList(fields[i].FieldType)?"Count":"Length")};\n");

                   
                        if(CheckTypeIsChildOfCoreDataEntity(innerType))
                        {
                            //sb.Append($"\t\tList<int>{entityTypesName} = new List<int>();\n");
                            sb.Append($"\t\tList<int>{entityIDsName} = new List<int>();\n");
                            //sb.Append($"\t\tif(data.{countName} >0)\n");
                        }
                        else
                        {
                            if (IsSerializedBaseType(innerType))
                            {
                                sb.Append($"\t\tList<int> {typesName} = new List<int>();\n");
                            }
                            sb.Append($"\t\tint {curIndexName} = 0;\n");
                            sb.Append($"\t\tList<int>{indexesName} = new List<int>(){{0}};\n");
                            sb.Append($"\t\tList<byte> {bytesName} = new List<byte>();\n");
                        }
                    
                        sb.Append($"\t\tfor(int i=0;i<data.{countName};i++)\n");

                        sb.Append("\t\t{\n");

                        if (CheckTypeIsChildOfCoreDataEntity(innerType))
                        {
                            sb.Append($"\t\t\tif(this.{fields[i].Name}[i] == null)\n \t\t\t\tcontinue;\n\n");
                            //sb.Append($"\t\t\t{entityTypesName}.Add({fields[i].Name}[i].GetEntityTypeID());\n");
                            sb.Append($"\t\t\t{entityIDsName}.Add({fields[i].Name}[i].entityId);\n");

                            //sb.Append($"\t\t\tbyte[] curBytes = CoreDataEntityFactory.EntitySerialize(this.{ fields[i].Name}[i]);\n");
                        }
                        else
                        {
                            sb.Append($"\t\t\tif(this.{fields[i].Name}[i] == null)\n \t\t\t\tcontinue;\n\n");

                            if (IsSerializedBaseType(innerType))
                            {
                                sb.Append($"\t\t\t{typesName}.Add(this.{fields[i].Name}[i].type);\n");
                            }

                            sb.Append($"\t\t\tbyte[] curBytes = this.{fields[i].Name}[i].Write();\n");

                            sb.Append($"\t\t\t{curIndexName} += curBytes.Length;\n");

                            sb.Append($"\t\t\t{indexesName}.Add({curIndexName});\n");

                            sb.Append($"\t\t\t{bytesName}.AddRange(curBytes);\n");
                        }
                        
                        sb.Append("\t\t}\n");

                        if (CheckTypeIsChildOfCoreDataEntity(innerType))
                        {
                            //sb.Append($"\t\tdata.{entityTypesName} =  CommonFunctions.Serialize<List<int>>({entityTypesName});\n");
                            sb.Append($"\t\tdata.{entityIDsName} =  CommonFunctions.Serialize<List<int>>({entityIDsName});\n");
                        }
                        else
                        {
                            if (IsSerializedBaseType(innerType))
                            {
                                sb.Append($"\t\tdata.{typesName} =  CommonFunctions.Serialize<List<int>>({typesName});\n");
                            }

                                sb.Append($"\t\tdata.{indexesName} =  CommonFunctions.Serialize<List<int>>({indexesName});\n");
                                sb.Append($"\t\tdata.{dataFieldName} = {bytesName}.ToArray();\n\n");
                        }
                    }
                    else
                    {
                        //var interfaces = fields[i].FieldType.GetInterfaces();
                        //var ISerialize = System.Array.Find(interfaces, e => e.Equals(typeof(ISerialize)));
                        bool fieldIsStruct = fields[i].FieldType.IsValueType;
                    
                        if (CheckTypeIsChildOfISerializeOrISerializeStruct(fields[i].FieldType))
                        {
                            //string entityTypeName = $"_{fields[i].Name}_EntityType";
                            string entityIDName = $"_{fields[i].Name}_EntityID";
                            if (CheckTypeIsChildOfCoreDataEntity(fields[i].FieldType))
                            {
                                sb.Append($"\t\tdata.{entityIDName} = this.{fields[i].Name} == null? -1 : this.{fields[i].Name} .entityId;\n");
                            }
                            else if (IsSerializedBaseType(fields[i].FieldType))
                            {
                                string typeName = $"_{fields[i].Name}_Type";
                                sb.Append($"\t\tdata.{typeName} =  this.{fields[i].Name}.type;\n");

                                sb.Append($"\n\t\tif(this.{fields[i].Name} != null)\n");
                                sb.Append($"\t\t\tdata.{dataFieldName} = {fields[i].FieldType.Name}.WriteBytes(this.{fields[i].Name});\n");
                            }
                            else
                            {
                                sb.Append($"\t\tdata.{dataFieldName} = this.{fields[i].Name}{(fieldIsStruct ? "" : "?")}.Write();\n");
                            }
                        }
                        else
                        {
                            if (IsSerializedBaseType(fields[i].FieldType))
                            {
                                sb.Append($"\t\tdata.{dataFieldName} = this.{fields[i].Name};\n");
                            }
                            else
                            {
                                string typeStr = GetTypeString(fields[i].FieldType);
                                sb.Append($"\t\tdata.{dataFieldName} = CommonFunctions.Serialize<{typeStr}>(this.{fields[i].Name});\n");
                            }
                        }
                    }
                }
                else
                {
                    sb.Append($"\t\tdata.{dataFieldName} = this.{fields[i].Name};\n");
                }
            }
            sb.Append($"\t\treturn CommonFunctions.Serialize(data);");

        sb.Append("\t}\n");

        sb.Append("}\n");

        return sb.ToString() ;
    }

    static bool IsSerializedBaseType(Type type)
    {
        //if (type.Equals(typeof(OperationBase)))
        //{
        //    return true;
        //}
      
        return false;
    }
    static bool IsChildOfSerializedBaseType(Type type)
    {
        string str = "";
        return IsChildOfSerializedBaseType(type, out str);
    }
    static bool IsChildOfSerializedBaseType(Type type, out string BaseTypeName)
    {
        BaseTypeName = "";

        Type curType = type;
        while (curType != null && !curType.Equals(typeof(object)))
        {
            //if (curType.Equals(typeof(OperationBase)))
            //{
            //    BaseTypeName = "OptBase";
            //    return true;
            //}

            //if (curType.Equals(typeof(DescBase)))
            //{
            //    BaseTypeName = "DescBase";
            //    return true;
            //}
            curType = curType.BaseType;
        }
        return false;
    }



    public static bool CheckTypeIsChildOfISerializeOrISerializeStruct(Type type)
    {
        if (type == null)
        {
            GameDebug.LogError("type == null");
            return false;
        }

        Type curType =  type.BaseType;
        while (curType != null && !curType.Equals(typeof(object)))
        {
            if (curType.Equals(typeof(ISerialize)))
            {
                return true;
            }
            curType = curType.BaseType;
        }

        var interfaces = type.GetInterfaces();
        var ISerialize = System.Array.Find(interfaces, e => e.Equals(typeof(ISerializeStruct)));
        if (ISerialize != null)
            return true;

        return false;
    }

    /// <summary>
    /// 是否是CoreDataEntity子类
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    static bool CheckTypeIsChildOfCoreDataEntity(Type type,bool containsCoreDataEntity = true)
    {
        if(type == null)
            return false;

        Type curType = containsCoreDataEntity?type: type.BaseType;
        while (curType != null && !curType.Equals(typeof(object)))
        {
            //if(curType.Equals(typeof(CoreDataEntity)))
            //{
            //    return true;
            //}
            curType = curType.BaseType;
        }
        return false;
    }

    public static string GetTypeString(Type type)
    {
        string typeStr = type.ToString();
        if (typeStr.Contains("List"))
       // if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>))
        {
            //foreach (var a in type.GetGenericArguments())
            //    GameDebug.Log($"{type.FullName} GetGenericArguments: {a.GetType().FullName}");

            int beginIndex = typeStr.IndexOf("[");
            int endIndex = typeStr.IndexOf("]");
            typeStr = string.Format("List<{0}>", typeStr.Substring(beginIndex+1, endIndex - beginIndex - 1));
        }

        return typeStr;
    }

    /// <summary>
    /// 获取列表元素的类型
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static string GetListOrArrayInnerTypeString(Type type)
    {
        string typeStr = type.ToString();
        if (typeStr.Contains("List"))
        {
            int beginIndex = typeStr.IndexOf("[");
            int endIndex = typeStr.IndexOf("]");
            typeStr = typeStr.Substring(beginIndex + 1, endIndex - beginIndex - 1);
        }
        else if (typeStr.Contains("[]"))
        {
            typeStr = typeStr.Replace("[]", "");
           // GameDebug.LogError($"GetListOrArrayInnerTypeString  type:{type}  typeStr:{typeStr}");
        }
        return typeStr;
    }

    static string Type2ProtoBufDataFormat(Type type)
    {
#if PROTO2
        if (type.Equals(typeof(int)) || type.Equals(typeof(long)) || type.Equals(typeof(double)) || type.IsEnum)
        {
            return ProtoBuf.DataFormat.TwosComplement.ToString();
        }
        else if (type.Equals(typeof(float)))
        {
            return ProtoBuf.DataFormat.FixedSize.ToString();
        }
        else
        {
            return ProtoBuf.DataFormat.Default.ToString();
        }
#else
        return "";
#endif
    }

    /// <summary>
    /// 生成protobuf c#文件后要注释掉原c#文件中的序列化字段
    /// </summary>
    static void RemoveOriginalSharpFileSerializeFields(List<CSharpClass> classes)
    {
        foreach(var sharpClass in classes)
        {
            GameDebug.Log($"注释掉原c#文件中的序列化字段 正在处理:{sharpClass.Name}");

            string[] fileLines = File.ReadAllLines(sharpClass.scriptPath);

            var typeFields = GetSerilizedFields(sharpClass.type);

            foreach (var field in typeFields)
            {
                GameDebug.Log($"准备找字段：{field.Name}");
                for (int i=0;i< fileLines.Length; i++)
                {
                    string fieldWord = " " + field.Name;
                    if (fileLines[i].Contains(fieldWord))
                    {
                        GameDebug.Log($"在第{i+1}行找到{fieldWord}  line{i + 1}:{fileLines[i]} ");

                        int index = fileLines[i].IndexOf(fieldWord);
                        string pre = fileLines[i].Substring(0, index);

                        string preWord = GetPreFirstWord(pre);

                        bool isType= false;
                        Type type = Type.GetType(preWord);
                        if (IsBaseType(preWord))
                            isType = true;
                        else
                            isType = Assembly.Load("BattleData").GetType(preWord) != null;

                        if(isType)
                        {
                            fileLines[i] = fileLines[i].Insert(0, "//");
                            break;
                        }
                        else
                        {
                            GameDebug.Log($"{preWord} 不是类型");
                        }
                    }
                }
            }

            string newContent = "";
            for (int i = 0; i < fileLines.Length; i++)
                newContent += fileLines[i] + "\n";

            File.WriteAllText(sharpClass.scriptPath, newContent);
        }
    }



    /// <summary>
    /// 获取关键字前面的第一个词
    /// </summary>
    /// <param name="preStr"></param>
    /// <returns></returns>
    static string GetPreFirstWord(string preStr)
    {
        GameDebug.Log($"获取关键字：{preStr}");
        int right = -1;
        int left = -1;
   
        string res = "";
        for(int i=preStr.Length - 1; i >= 0; i--)
        {
            if (!preStr[i].Equals(' '))
            {
                if (right < 0)
                {
                    GameDebug.Log($"right :{preStr[i]}");
                    right = i;
                }
            }
            if (right>= 0)
            {
                if (preStr[i].Equals(' '))
                {
                    if (left < 0)
                    {
                        GameDebug.Log($"left :{preStr[i]}");
                        left = i + 1;
                    }
                }
            }

            if (right >= 0 && left >= 0)
            {
                res = preStr.Substring(left, right - left+1);
                GameDebug.Log($"前面找到word:[{res}]");
                return res;
            }

        }
        GameDebug.Log("前面找不到word  preStr:" + preStr);
        return res;
    }

    /// <summary>
    /// 清理文件夹下所有文件
    /// </summary>
    /// <param name="path"></param>
    static void DirClearFiles(string path)
    {
        if (!Directory.Exists(path))
            Directory.CreateDirectory(path);

        var oldFiles = Directory.GetFiles(path);
        foreach (var old in oldFiles)
        {
            if (File.Exists(old))
                File.Delete(old);

            if (Directory.Exists(old))
                Directory.Delete(old);
        }
    }


    /// <summary>
    /// 从文本解析类信息
    /// </summary>
    /// <param name="assembly"></param>
    /// <param name="content"></param>
    /// <returns></returns>
    static List<CSharpClass> ParseClass(Assembly assembly,string scriptPath,string keyword)
    {
        string content = File.ReadAllText(scriptPath);

        List<CSharpClass> res = new List<CSharpClass>();

        List<int> classNameIndexes = new List<int>();

        string[] lines = content.Split('\n');
        for(int i = 0; i < lines.Length; i++)
        {
            string line = lines[i];
            if (line.Contains(keyword))
            {
#if LOG
                GameDebug.Log($"正在寻找：{line}");
#endif
                int index = line.IndexOf(keyword);

                if (index < 0)
                    continue;

                string pre = line.Substring(0, index);

                if (pre.Contains("//"))
                    continue;

                string className = "";

                string post = line.Substring(index, line.Length - index);
                string[] names = post.Split(' ');
                List<string> nameList = new List<string>();
                names.ForEach(e =>
                {
                    if (!string.IsNullOrWhiteSpace(e))
                    {
                        nameList.Add(e);
                    }
                });
                if (nameList.Count > 1)
                {
                    className = nameList[1];
                }
                className = className.Trim();

                if(className.Contains(":"))
                {
                    int maoIndex = className.IndexOf(":");
                    className = className.Substring(0, maoIndex);
                }

                if (string.IsNullOrEmpty(className))
                {
                    GameDebug.LogError($"解析失败  line:{line}  post:{post}  names:{names.GetArrStr()} ");
                    continue;
                }
                string[] keys = pre.Split(' ');
                List<string> keysList = new List<string>(keys);
                keysList.Remove("");
                keysList.Remove(" ");

                CSharpClass sharpClass = new CSharpClass();
                Type type = assembly.GetType(className);
                if (type == null)
                {
                    GameDebug.LogError($"GetType Fail  className:{className} assembly:{assembly.FullName}");

                    //var test = Assembly.Load("BattleData").GetType(className);
                    //GameDebug.Log($"try again {className}  类:{test} ");
                }
#if LOG
                GameDebug.Log($"类{type} 的名称是{className}  修饰 有{keys.GetArrStr()}");
#endif
                sharpClass.type = type;
                sharpClass.Name = className;
                sharpClass.keys = keysList.ToArray();
                sharpClass.scriptPath = scriptPath;

                if(res.Find(e=>e.Name == className) == null)
                    res.Add(sharpClass);
                
                string curContent = content;
                int curBeginIndex = 0;
                int curIndex = 0;
                int hitIndex = 0;
                bool findSuc = false;

                int tryCount = 0;
                while (tryCount<20)
                {
                    tryCount ++;
                    
                    //全字匹配（类名前有空格，类名后不是字母数字下划线
                    curIndex = curContent.IndexOf(" "+className);

                    if(curIndex < 0)
                    {
                        GameDebug.Log($"未找到class ：{className}");
                        break;
                    }
                  
                    int nextIndex = curIndex + className.Length + 1;

                    char next = '_';
                    if(nextIndex < curContent.Length)
                        next = curContent[nextIndex];

                    //GameDebug.LogError($"className：{className}   next:[{next}]");

                    if (!char.IsLetter(next) && !char.IsDigit(next) && !next.Equals('_'))
                    {
                        //if (curIndex < 0)
                        //{
                        //    GameDebug.Log($"未找到class ：{className}");
                        //    // break;
                        //}
                        //else
                        {
                            int keyLength = keyword.Length;
                            //找类名前是否有class关键字
                            for (int j = curIndex; j > 0; j--)
                            {
                                if (curContent[j] == ' ')
                                    continue;

                                if (curContent[j].Equals(keyword[keyLength - 1 - hitIndex]))
                                {
                                    hitIndex++;
                                }
                                else
                                {
#if LOG
                                    GameDebug.Log($"前面找不到class content[j]:[{curContent[j]}]   hitIndex:{hitIndex}  keyword:{keyword}");
#endif
                                    hitIndex = 0;
                                    break;
                                }
                                if (hitIndex >= keyLength)
                                {
                                    int totalIndex = curBeginIndex + curIndex;
                                    classNameIndexes.Add(totalIndex);
                                    findSuc = true;
#if LOG
                                    string testGetName = content.Substring(totalIndex, className.Length+1);
                                    GameDebug.Log($"找到class ：{type}   totalIndex:{totalIndex}  testGetName:{testGetName}");
#endif
                                    break;
                                }
                            }

                            if (findSuc)
                            {
                                break;
                            }
                        }
                    }
                    else
                    {
                        GameDebug.Log($"不是全字匹配 className：{className}   next:[{next}]");
                    }

                    int newBegin = curIndex + className.Length+1;
                    try
                    {
                        curContent = curContent.Substring(newBegin, curContent.Length - newBegin);
                        curBeginIndex += newBegin;
                    }
                    catch(Exception e)
                    {
                        GameDebug.Log($"超出范围 未找到class  newBegin:{newBegin}  length：{content.Length - newBegin}  content.Length:{content.Length}");
                        //break;
                    }
                    //GameDebug.Log($"curContent：{curContent}");
                }
            }
        }

        for(int i=0;i<classNameIndexes.Count;i++)
        {
            int curIndex = classNameIndexes[i];
#if LOG
            GameDebug.Log($"class {res[i].Name} 序号是{curIndex}");
#endif
            int nextIndex = content.Length;
            if (i + 1 < classNameIndexes.Count)
                nextIndex = classNameIndexes[i + 1];

            string postContent = content.Substring(curIndex, nextIndex - curIndex);

            if (string.IsNullOrEmpty(postContent))
            {
                GameDebug.LogError($"postContetn == null class:{res[i].Name} ");
                continue;
            }

            int beginIndex = postContent.IndexOf("{");
            int endIndex = postContent.LastIndexOf("}");

            res[i].content = postContent.Substring(beginIndex, endIndex - beginIndex + 1);
#if LOG
            GameDebug.Log($"res[i]== null:{res[i] == null}  type==null:{res[i].type == null}");
            GameDebug.Log($"class {res[i].Name} 的内容是{res[i].content}");
#endif
        }

        return res;

    }

    


    static string GetFileNameWithPath(string path,bool withExtension)
    {
        string protoPath = withExtension? path: Path.GetFileNameWithoutExtension(path);
        protoPath = protoPath.Replace("\\", "/");
        int last = protoPath.LastIndexOf("/");
        last = last < 0 ? 0 : last;
        string fileName = protoPath.Substring(last, protoPath.Length - last);
        return fileName;
    }
    
    static void SaveFile(string path, string content)
    {
        var bytes = Encoding.UTF8.GetBytes(content);
        File.WriteAllBytes(path, bytes);
    }

    /// <summary>
    /// 基本类型
    /// </summary>
    static bool IsBaseType(Type type)
    {
        return
            type == typeof(bool) ||
            type == typeof(char) ||
            type == typeof(short) ||
            type == typeof(ushort) ||
            type == typeof(int) ||
            type == typeof(uint) ||
            type == typeof(long) ||
            type == typeof(ulong) ||
            type == typeof(string) ||
            type == typeof(float) ||
            type == typeof(double) ||
             type == typeof(byte) 
            // ||type == typeof(byte[])

            //type == typeof(FixedFloat) ||
            //type == typeof(FixedVec2) ||
            //type == typeof(FixedVec3)
            ;
    }
    public static bool IsBaseType(string type)
    {
        return IsBaseType(Type.GetType(type));
    }

    public static string GetFieldTypeProtoString(Type fieldType)
    {
        if (fieldType.Equals(typeof(double)))
            return "double";
        else if (fieldType.Equals(typeof(float)))
            return "float";
        else if (fieldType.Equals(typeof(int)))
            return "int32";
        else if (fieldType.Equals(typeof(long)))
            return "int64";
        else if (fieldType.Equals(typeof(uint)))
            return "uint32";
        else if (fieldType.Equals(typeof(ulong)))
            return "uint64";
        else if (fieldType.Equals(typeof(bool)))
            return "bool";
        else if (fieldType.Equals(typeof(string)))
            return "string";
        else
            return "bytes";
    }

    public static FieldInfo[] GetSerilizedFields(Type type)
    {
        List<FieldInfo> res = new List<FieldInfo>();
        List<FieldInfo> fields =  new List<FieldInfo>(type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public));

       // fields.AddRange(type.BaseType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public));

        string str = "字段有:";

        foreach (var field in fields)
        {
            str += " " + field.Name;

            if (field.IsNotSerialized)
                continue;

            //if (field.FieldType.Equals(typeof(CoreEntityCollection)))
            //    continue;

            res.Add(field);

        }
#if LOG
        GameDebug.Log(str);
#endif
        return res.ToArray();
    }

 
}
